In [ ]:
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
1. Familiar with Python
2. Completed Handbook 2/Part 9: Data Curation
1. Preprocessing a builtin dataset (cifar-10)
2. Train dataset for a few epochs
3. Use same model architecture for larger number of classes (cifar-100)
4. Use image augmentation
In [ ]:
from keras.datasets import cifar10, cifar100
from keras.utils import to_categorical
Let's start with a function that will create our model using a simple CNN architecture, as follows:
Stem Group
We use the current convention of replacing a single 5x5 convolution with two 3x3 convolutions and delay downsampling to later in the network (i.e., strides=1).
Convolutional Blocks
We will use a VGG style of using sequential convolutional layers in groups, where each group doubles the number of filters, and downsample the feature maps at the end of the group using max pooling. We deviate from VGG, by using a current convention of factorizing pairs of 3x3 filters with a 3x3 and a 1x1 (bottleneck) filter.
Classifier
We will add a hidden dense layer to the classifier, and then follow it by a current convention of using a global averaging instead of flatten --this will reduce the number of parameters, where it's the current convention if the feature maps are 4x4 or greater.
You fill in the blanks (replace the ??), make sure it passes the Python interpreter.
You will need to:
1. Set the loss function for compiling the model.
In [ ]:
from keras import Input, Model
from keras.layers import Conv2D, MaxPooling2D, Dropout, BatchNormalization, GlobalAveragePooling2D, Dense
def convNet(input_shape, nclasses):
def stem(inputs, nb_filters):
''' Stem Convolutional Group '''
# Use two 3x3 convolutional layers (no downsampling, strides=1)
x = Conv2D(nb_filters, (3, 3), strides=1, padding='same', activation='relu')(inputs)
x = Conv2D(nb_filters, (3, 3), strides=1, padding='same', activation='relu')(x)
# Downsample with Max Pooling
x = MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')(x)
x = Dropout(0.25)(x)
return x
def conv_block(x, nb_filters):
''' Convolutional Block '''
# A 3x3 and 1x1 factorization of two 3x3 convolutional layers
x = Conv2D(nb_filters, (3, 3), strides=1, padding='same', activation='relu')(x)
x = Conv2D(nb_filters, (1, 1), strides=1, padding='same', activation='relu')(x)
# Downsample with Max Pooling
x = MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')(x)
return x
def classifier(x, nclasses):
''' Classifier '''
x = GlobalAveragePooling2D()(x)
x = Dense(128, activation='relu')(x)
x = Dense(nclasses, activation='softmax')(x)
return x
# Input and Stem Group
inputs = Input(input_shape)
x = stem(inputs, 32)
# Two Convolutional Blocks, each doubles the number of filters
for nb_filters in [64, 128]:
x = conv_block(x, nb_filters)
outputs = classifier(x, nclasses)
model = Model(inputs, outputs)
# Let's compile the model. We will use the defacto optimizer for optimization (adam)
# HINT: For the loss function, think categorical (multi-class) and cross entropy.
model.compile(loss='??', optimizer='adam', metrics=['accuracy'])
return model
Let's get the Keras builtin dataset for CIFAR-10.The image data from the load_data() is not preprocessed. That is, the labels are not converted to one-hot encoded and the image data is still in it's original 8-bit integer values (0..255).
You will need to:
1. Specify the value to divide the pixel data by.
In [ ]:
import numpy as np
# Get the builtin CIFAR-10 dataset
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
# One-hot encode the labels
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
# Normalize the pixel data between 0 and 1
# HINT: You are squashing the values from 0 and 255, what do you think you need to divide by?
x_train = (x_train / ??).astype(np.float32)
x_test = (x_test / ??).astype(np.float32)
In [ ]:
model = convNet((32, 32, 3), 10)
model.summary()
In [ ]:
# Train the model using an in-memory feeding
model.fit(x_train, y_train, batch_size=32, epochs=3, validation_split=0.1, verbose=1)
score = model.evaluate(x_test, y_test)
print(score)
Let's get the Keras builtin dataset for CIFAR-100. This is a more challenging dataset in that it has 100 (instead of 10) classes, and fewer images per class (600 vs. 6000).
In the CIFAR-10, we used normalization on the pixel data. This time, we will use standardization.
You will need to:
1. Substract the mean from the train and test data.
In [ ]:
# Get the CIFAR-100 builtin dataset
(x_train, y_train), (x_test, y_test) = cifar100.load_data()
# One-hot encode the labels
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
# Standardize the pixel data (substract mean and divide by standard deviation of 1)
# HINT: We are substracting the mean!
mean = np.mean(x_train)
std = np.std(x_train)
x_train = ((x_train - ??) / std).astype(np.float32)
x_test = ((x_test - ??) / std).astype(np.float32)
In [ ]:
model = convNet((32, 32, 3), 100)
model.summary()
In [ ]:
model.fit(x_train, y_train, batch_size=32, epochs=3, validation_split=0.1, verbose=1)
score = model.evaluate(x_test, y_test)
print(score)
Let's now use Keras ImageDataGenerator to add some image augmentation. We will do the following:
1. Vertical and Horizontal flips.
2. Random Rotation +/- 30 degrees.
Note, accuracy will be low (brevity) --to demonstrate using ImageDataGenerator.
You will need to:
1. Reset the training data to the subset not including the validation data.
In [ ]:
from keras.preprocessing.image import ImageDataGenerator
# Create the generator for doing Image Augmentation
datagen = ImageDataGenerator(vertical_flip=True, horizontal_flip=True, rotation_range=30)
# For validation split, calculate the pivot point first. -i.e, where one part is training
# and one part is validation
pivot = int(len(x_train) * 0.9)
# So for validation, it's all the data after the pivot point
x_val = x_train[pivot:]
y_val = y_train[pivot:]
# For the remainig (before pivot point) it's the training
# HINT: it's everything before the pivot point
x_train = x_train[??]
y_train = y_train[??]
model = convNet((32, 32, 3), 100)
model.fit_generator(datagen.flow(x_train, y_train, batch_size=32), epochs=3, steps_per_epoch=len(x_train)/32,
validation_data=(x_val, y_val), verbose=1)
score = model.evaluate(x_test, y_test)
print(score)